package com.jay.studyproject.interview;

/**
 * 面试题
 */
public class Demo6{

    /**
     *
     1. Activity的生命周期？
     Activity启动 ----> onCreate() ------> onStart() --------->onResume()
     点击Home键回到主界面(Activity不可见) --->onPause() ----> onStop()
     当我们再次回到原Activity时 ---> onRestart() --> onStart() -----> onResume()
     退出当前Activity时 --> onPause() --->onStop() -----> onDestroy()
     (1)onCreate()方法：活动第一次创建的时候被调用，常做初始化的操作，比如加载布局（setContentView），绑定事件（findViewById）。表示Activity正在创建。
     (2)onStart()方法：活动由不可见到可见的时候被调用，表示Activity正在启动，此时Activity可见但不在前台。
     (3)onResume（）方法：活动准备好和用户进行交互时调用。表示Acitivity获得焦点，此时Activity可见且在前台。
     (4)onPause（）方法：系统准备去启动或恢复另一个活动时调用。表示Activity正在停止，此时可做存储数据，停止动画等操作。
     (5)onStop（）方法：在活动完全不可见的时候调用。表示Activity即将停止。
     (6)onDestory（）方法：在活动被销毁之前调用，表示Activity即将销毁，常做回收工作、资源释放。
     (7)onRestart（）方法：在活动由停止状态变为运行状态之前调用。表示Activity即将重启。

     2.Fragment的生命周期？
     onAttach() ：
     当Fragment与Activity发生关联时调用。
     onCreate()：
     创建Fragment时被回调。
     onCreateView()：
     每次创建、绘制该Fragment的View组件时回调该方法，Fragment将会显示该方法返回的View 组件。
     onActivityCreated()：
     当 Fragment 所在的Activity被启动完成后回调该方法。
     onStart()：
     启动 Fragment 时被回调，此时Fragment可见。
     onResume()：
     恢复 Fragment 时被回调，获取焦点时回调。
     onPause()：
     暂停 Fragment 时被回调，失去焦点时回调。
     onStop()：
     停止 Fragment 时被回调，Fragment不可见时回调。
     onDestroyView()：
     销毁与Fragment有关的视图，但未与Activity解除绑定。
     onDestroy()：
     销毁 Fragment 时被回调。
     onDetach()：
     与onAttach相对应，当Fragment与Activity关联被取消时调用。
     生命周期调用
     1）创建Fragment
     onAttach() —> onCreate() —> onCreateView() —> onActivityCreated() —> onStart() —> onResume()
     2）按下Home键回到桌面 / 锁屏
     onPause() —> onStop()
     3）从桌面回到Fragment / 解锁
     onStart() —> onResume()
     4）切换到其他Fragment
     onPause() —> onStop() —> onDestroyView()
     5）切换回本身的Fragment
     onCreateView() —> onActivityCreated() —> onStart() —> onResume()
     6） 按下Back键退出
     onPause() —> onStop() —> onDestroyView() —> onDestroy() —> onDetach()

     3. Activity的4大启动模式，与开发中需要注意的问题，如onNewIntent() 的调用
     1、Standard：是活动默认的启动模式，在不进行显式指定的情况下，所有活动都会自动使用这种启动模式。系统不在乎这个活动是否已经在返回栈中存在，每次启动都会创建该活动的一个新的实例。
     2、SingleTop：在启动活动时，如果发现栈顶已经是该活动，则认为可以直接使用它，不会再创建。
     3、SingleTask：在启动活动时，会首先在返回栈中检查是否存在该活动的实例，如果发现已经存在则直接使用，并把这个活动只还是那个的所有活动都统统出栈。
     4、SingleInstance：指定这种模式的活动，会启用一个新的返回栈来管理这个活动，主要为了实现其他应用程序和本地应用程序共享这个活动实例。
     Activity第一次启动和已在返回栈中的启动流程
     （1）Activity的第一次创建启动流程：
     onCreate() -> onStart() ->onResume()
     （2）SingleTask模式的Activity在Intent触发下启动流程
     onNewIntent() ->onRestart() ->onStart() ->onResume()
     4.Activity如何保存状态的？
     　1. 第一种是使用savedInstanceState。savedInstanceState是一个Bundle对象，类似HashMap以键值对的形式存在。通常用于保存当Activity被另一Activity遮挡或是覆盖时使用。
     　　2. 第二种是试用SharedPreference来保存。众所周知，SharedPreference是以xml格式存储数据。通常在当用户按下back或是home键。在Activity生命周期onPause()时使用SharedPreference记录当前状态，而在onResume()时，恢复其状态。
     5.请描诉Activity的启动流程，从点击图标开始。

     ①点击桌面App图标，Launcher进程采用Binder IPC向system_server进程发起startActivity请求；

     ②system_server进程接收到请求后，向zygote进程发送创建进程的请求；

     ③Zygote进程fork出新的子进程，即App进程；

     ④App进程，通过Binder IPC向sytem_server进程发起attachApplication请求；

     ⑤system_server进程在收到请求后，进行一系列准备工作后，再通过binder IPC向App进程发送scheduleLaunchActivity请求；

     ⑥App进程的binder线程（ApplicationThread）在收到请求后，通过handler向主线程发送LAUNCH_ACTIVITY消息；

     ⑦主线程在收到Message后，通过发射机制创建目标Activity，并回调Activity.onCreate()等方法。

     ⑧到此，App便正式启动，开始进入Activity生命周期，执行完onCreate/onStart/onResume方法，UI渲染结束后便可以看到App的主界面。



     6.Service的生命周期是什么样的？Service两种生命周期以及区别？你会在什么情况下使用Service？
     1、Started Service的生命周期：
     onCreate()：创建服务
     onStartCommand()：服务开始运行（在2.0以前版本中，使用onStart()回调方法）
     onDestroy() ：服务被停止
     【详细说明：】
     在程序中调用context.startService()： 会触发执行Service生命周期中的onCreate()、onStartCommand()回调方法，此时服务就开始正式运行；
     如果Service还没有运行，则android先调用onCreate()然后调用onStartCommand()；如果Service已经运行，则只调用onStartCommand()，所以一个Service的onStartCommand方法可能会重复调用多次；
     如果在程序中调用context.stopService()：会触发执行Service生命周期中的onDestroy()回调方法，会让服务停止；
     stopService()的时候直接onDestroy，如果是调用者自己直接退出而没有调用stopService()的话，Service会一直在后台运行。该Service的调用者再启动该Service后可以通过stopService关闭Service；stopSelf()
     所以StartService的生命周期为：onCreate –> onStartCommand(可多次调用) –> onDestroy。
     2、Bind Service的生命周期：
     onCreate()：创建服务
     onBind()：绑定服务，服务开始运行
     onUnbind()：取消绑定
     onDestroy() ：服务被停止
     【详细说明：】
     在程序中调用：context.bindService()会触发执行Service生命周期中的onCreate()、onBind()回调方法，此时服务开始运行；
     onBind将返回给客户端一个IBind接口实例，IBind允许客户端回调服务的方法，比如得到Service运行的状态或其他操作。此后调用者（Context，例如Activity）会和Service绑定在一起；
     如果调用Service的调用者Context退出了，那么会依次调用Service生命周期中的onUnbind()、onDestroy()回调方法，会让服务停止；
     所以BindService的生命周期为：onCreate –> onBind(只一次，不可多次绑定) –> onUnbind –> onDestory。
     【备注：】
     Service是不能自己启动的，只有通过 Context 对象调用startService() 和bindService() 方法来启动。
     在Service每一次的开启关闭过程中，只有onStartCommand()可被多次调用(通过多次startService调用)，其他onCreate()、onBind()、onUnbind()、onDestory()在一个生命周期中只能被调用一次。
     Service可以在和多场合的应用中使用，比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放，比如检测SD卡上文件的变化，再或者在后台记录你地理信息位置的改变等等，总之服务总是藏在后头的

     7.ContentProvider如何自定义与使用场景是什么？
     ContentProvider是Android提供给上层的一个组件，主要用于实现数据访问的统一管理和数据共享。这里的数据管理是通过定义统一的访问接口来完成，
     如增删改查。同时，它采用了类似Internet的URL机制，将数据以URI的形式来标识，这样其他App就可以采用一套标准的URI规范来访问同一处数据，
     而不用关心具体的实现细节。我们知道在Android系统中可能会涉及到一个App的数据被其他App使用的情况，比如通讯录，日历，短信等，
     这时就需要一套能实现数据共享的机制，这里的ContentProvider就可以提供该功能，其底层使用了binder来完成App进程之间的通信，
     同时使用匿名共享内存来作为共享数据的载体。当然为了保证数据访问的安全性，ContentProvider还对每处的数据URI增加了权限管理机制，以控制该数据的访问者及访问方式。
     自定义ContentProvider
     1、编写一个类，必须继承自ContentProvider类；
     2、实现ContentProvider类中所有的抽象方法；
     需要实现：onCreate() 、getType() 、query() 、insert() 、update()、delete() 等方法。
     【备注】
     ContentProvider暴露出来的数据和方法并不是给自身调用的，而是给其他应用程序来调用。其他应用程序通过其ContentResolver对象调用的query() 、insert() 、update()、delete()
     等方法就是我们在这里暴露出来的ContentProvider类中的重写后的query() 、insert() 、update()、delete() 方法。

     3、定义ContentProvider的Uri。这个Uri是ContentResolver对象执行CRUD操作时重要的参数；

     4、使用UriMatcher对象映射Uri返回代码；

     5、在AndroidMainfest.xml文件中使用<provider>标签注册ContentProvider。

     ContentProvider类中六个抽象方法的说明：
     onCreate()   初始化provider
     query()      返回数据给调用者
     insert()     插入新数据到ContentProvider
     update()     更新ContentProvider已经存在的数据
     delete()     从ContentProvider中删除数据
     getType()    返回ContentProvider数据的Mime类型

     【备注】
     ContentProvider是单例模式的，当多个应用程序通过使用ContentResolver 来操作使用ContentProvider 提供的数据时，
     ContentResolver 调用的数据操作会委托给同一个ContentProvider 来处理。这样就能保证数据的一致性。

     8.BroadcastReciver的静态注册与动态注册的区别？
     动态注册的广播接收器可以自由的控制注册和取消，有很大的灵活性。但是只能在程序启动之后才能收到广播，此外，不知道你注意到了没，
     广播接收器的注销是在onDestroy()方法中的。所以广播接收器的生命周期是和当前活动的生命周期一样。
     静态注册的广播不受程序是否启动的约束，当应用程序关闭之后，还是可以接收到广播。


     9.Fragment add与replace的区别，分别对Fragment的生命周期影响
     1. 如果当前Activity同一个id还没有添加Fragment,replace操作和add操作一样。
     即执行两者操作生命周期变化：onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume,
     Fragment所依附的Activity销毁时，执行onPause->onStop->onDestoryView->onDestory->onDetach
     2. 如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例一样，replace无效果。
     3. 如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例不一样，replace操作会转换为 remove和add操作，即删除旧的Fragment,添加新的Fragment。
     旧的Fragment执行 onPause->onStop->onDestoryView->onDestory->onDetach
     新的Fragment执行 onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume

     10.事件分发机制是什么过程？
     当点击事件发生时，首先Activity将TouchEvent传递给Window，再从Window传递给顶层View。TouchEvent会最先到达最顶层 view 的 dispatchTouchEvent(事件的分发) ，
     然后由 dispatchTouchEvent 方法进行分发，如果dispatchTouchEvent返回true ，则整个事件将会被销毁，如果dispatchTouchEvent返回 false ，
     则交给上层view的 onTouchEvent(事件的处理)方法来开始处理这个事件，如果 onInterceptTouchEvent (事件的拦截)返回 true ，也就是拦截掉了，
     则交给自身的 onTouchEvent 来处理，如果 onInterceptTouchEvent 返回 false ，那么事件将继续传递给子 view ，由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。
     如果事件传递到某一层的子 view 的 onTouchEvent 上了，且这个方法返回了 false ，那么这个事件会从这个 view 往上传递，都是 onTouchEvent 来接收，
     直到onTouchEvent返回true为止。而如果传递到最顶view的 onTouchEvent 也返回 false 的话，这个事件就会消失。


     11.事件冲突怎么解决？
     内部拦截法
     内部拦截法的思路是子View在dispatchTouchEvent方法中通过调用requestDisallowInterceptTouchEvent(true)方法，禁止父View拦截事件。并在合适的场景将其置为fase允许拦截。
     外部拦截法
     部拦截法的思路是由父View通过重写onInterceptTouchEvent方法，在合适的场景拦截事件。
     应用场景: 左右滑动和上下滑动

     12.View中onTouch，onTouchEvent和onClick的执行顺序
       onTouchListener的onTouch方法优先级比onTouchEvent高，会先触发。
       假如onTouch方法返回false会接着触发onTouchEvent，反之onTouchEvent方法不会被调用。
       内置诸如click事件的实现等等，都基于onTouchEvent，假如onTouch返回true，这些事件将不会被触发。
     顺序为:
     onTouch—–>onTouchEvent—>onclick

     13.怎么拦截事件 onTouchEvent如果返回false onClick还会执行么？
     onInterceptTouchEvent(MotionEvent ev) 方法，从方法名称可知这个方法是用来拦截事件的,返回值为boolean类型，true代表本类要拦截此事件，
     此事件不再往子类传递;false代表不拦截，此事件继续往子类传递。Activity和View没有此方法。Activity是第一个接收到触摸事件的非系统类(因为是自己继承的Activity),
     它是不能进行事件拦截的，必须要要把事件传递给真正意义上的视图。而View因为没有子类，事件到了这里本身就不会再进行传递，所有没有拦截的必要。

     14.动画的分类以及区别
     Android动画可以分为帧动画（Frame Animation）、补间动画（Tweened Animation）和属性动画。
     比较：
     a、属性动画是真正的实现了view的移动，补间动画对view的移动更像是在不同地方绘制了一个影子，实际的对象还是处于原来的地方。

     b、属性动画会使Activity无法释放而导致内存泄漏，而补间动画却没有问题。因此，使用属性动画时切记在Activity执行 onStop 方法时顺便将动画停止。

     c、xml 文件实现的补间动画，复用率极高。在Activity切换，窗口弹出时等情景中有着很好的效果。

     d、使用帧动画时需要注意，不要使用过多特别大的图，容易导致内存不足。

     帧动画
     ，最容易实现的一种动画，这种动画更多的依赖于完善的UI资源，他的原理就是将一张张单独的图片连贯的进行播放，从而在视觉上产生一种动画的效果，可以说，
     图片资源决定了这种方式可以实现怎样的动画。有点类似于某些软件制作gif动画的方式。

     注：android：oneshot="false" ，这个oneshot 的含义就是动画执行一次（true）还是循环执行多次。

     补间动画
     ，可以分为四种形式，分别是 alpha（淡入淡出），translate（位移），scale（缩放大小），rotate（旋转）。补间动画的实现，一般会采用xml 文件的形式，
     代码会更容易书写和阅读，同时也更容易复用；动画的属性值需要动态的调整时，需要使用java代码实现。可以使用set 标签将多个动画组合。

     部分动画属性的含义：

     Interpolator
     主要作用是可以控制动画的变化速率 ，就是动画进行的快慢节奏。

     pivot
     决定了当前动画执行的参考位置。pivot 这个属性主要是在translate 和 scale 动画中，这两种动画都牵扯到view 的“物理位置“发生变化，所以需要一个参考点。
     而pivotX和pivotY就共同决定了这个点；它的值可以是float或者是百分比数值。

     属性动画
     ，顾名思义它是对于对象属性的动画。因此，所有补间动画的内容，都可以通过属性动画实现。属性动画实现很方便，同时动画可变化的值也有了更多的选择，
     动画所能呈现的细节也更多。属性动画可以使用xml文件的方式实现，但是属性动画的属性值一般会牵扯到对象具体的属性，更多是通过代码动态获取。

     ObjectAnimator
     ，这个类继承自ValueAnimator，使用这个类可以对任意对象的任意属性进行动画操作，而ValueAnimator是整个属性动画机制当中最核心的一个类。

     属性动画的运行机制
     是通过不断地对值进行操作来实现的，而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡，
     我们只需要将初始值和结束值提供给ValueAnimator，并且告诉它动画所需运行的时长，那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。
     除此之外，ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。

     属性动画的具体实现
     ，通过duration、startPropertyValue和endPropertyValue 等值，我们就可以定义动画运行时长，初始值和结束值，然后通过start方法开始动画，
     ValueAnimator是由TypeEvaluator 和TimeInterpolator 共同实现从初始值平滑过渡到结束值的。具体来说，TypeEvaluator 决定了动画如何从初始值过渡到结束值。

     TimeInterpolator 决定了动画从初始值过渡到结束值的节奏。

     TimeInterpolator
     ，是用来控制动画快慢节奏的。TimeInterpolator 继承自Interpolator。我们可以继承TimerInterpolator 以自己的方式控制动画变化的节奏，也可以使用Android 系统提供的Interpolator，
     通过setInterpolator 设置不同的Interpolator。

     15.RecyclerView与ListView的对比，缓存策略，优缺点。
     缓存机制对比
     1.层级不同：
     RecyclerView比ListView多两级缓存，支持多个离ItemView缓存，支持开发者自定义缓存处理逻辑，支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。
     具体来说： ListView(两级缓存), RecyclerView(四级缓存)

     优缺点
     1.ListView相比RecycleView的优点
     a.ListView实现添加HeaderView和FooderView有直接的方法
     b.分割线可以直接设置
     c.ListView实现onItemClickListence和onItemLongClickListence有直接的方法

     2.RecyclerView相比ListView的优点
     a.封装了ViewHodler，效率更高
     b.可以添加增删Item动画、侧滑功能等
     c.支持局部更新，可见才更新，不可见不更新
     d.插件式实现，各个功能模块化，解耦性强，使用起来更方便

     16.View的绘制原理
     View的绘制过程就是从ViewRoot的performTraversals方法开始的，它经过measure、layout、draw三个过程才能最终将一个View绘制出来：
     (1)measure用来测量View的宽和高。
     (2)layout用来确定View在父容器中放置的位置。
     (3)draw用来将view绘制在屏幕上。
     View的工作流程主要是指measure、layout、draw这三个流程，即测量、布局、绘制，其中measure确定View的测量宽高，layout确定View的最终宽高和上下左右的位置，draw将View绘制到屏幕上

     View的绘制流程
     自定义控件：
     1、组合控件。这种自定义控件不需要我们自己绘制，而是使用原生控件组合成的新控件。如标题栏。
     2、继承原有的控件。这种自定义控件在原生控件提供的方法外，可以自己添加一些方法。如制作圆角，圆形图片。
     3、完全自定义控件：这个View上所展现的内容全部都是我们自己绘制出来的。比如说制作水波纹进度条。。
     View的绘制流程：OnMeasure()——>OnLayout()——>OnDraw()
     第一步：OnMeasure()：测量视图大小。从顶层父View到子View递归调用measure方法，measure方法又回调OnMeasure。
     第二步：OnLayout()：确定View位置，进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程，即父View根据上一步measure子View所得到的布局大小和布局参数，将子View放在合适的位置上。
     第三步：OnDraw()：绘制视图。ViewRoot创建一个Canvas对象，然后调用OnDraw()。六个步骤：①、绘制视图的背景；②、保存画布的图层（Layer）；③、绘制View的内容；④、绘制View子视图，如果没有就不用；
     ⑤、还原图层（Layer）；⑥、绘制滚动条。


     17.invalidate() 和 postInvalicate() 区别
     invalidate()与postInvalidate()这两个都是刷新View的API，它们主要的区别是invalidate()可以在主线程（UI线程）中调用，而不能在子线程中调用，
     若在子线程中进行刷新view的操作需要配合handler来使用。而postInvalidate()可以在子线程中直接调用。

     18.Handler怎么进行线程通信，原理是什么？
     (1)应用程序启动的时候，在主线程中会默认调用了 Looper.preper()方法，初始化Looper对象并绑定到当前线程中，并在Looper内部维护一个MessageQueue
     (2)接着调用handler.sendMessage()发送消息，会通过MessageQueue.enqueueMessage()向MessageQueue中添加一条消息
     (3)主线程调用Looper.looper()开启循环，不断轮询消息队列，通过MessageQueue.next()取出消息
     (4)取出的message不为空则调用msg.target.dispatchMessage()传递分发消息，目标handler收到消息后会执行handler.handlerMessage()方法处理消息

     19.Handler如果没有消息处理是阻塞的还是非阻塞的？
     阻塞的。Looper.loop阻塞在MessageQueue的next方法中，有一个nativePollOnce的native方法，
     而在MessageQueue的enqueueMessage方法的最后nativeWake方法可以唤醒阻塞，使用了epoll机制
     在next()方法内部，如果有阻塞（没有消息了或者只有Delay的消息），会把mBlocked这个变量标记为true，
     在下一个Message进队时会判断这个message的位置，如果在队首并且时间满足条件，会调用nativeWake()方法唤醒线程！


     20.内存泄漏和溢出
     内存泄漏（memory leak）：是指程序在申请内存后，无法释放已申请的内存空间，导致系统无法及时回收内存并且分配给其他进程使用。
     通常少次数的内存无法及时回收并不会到程序造成什么影响，但是如果在内存本身就比较少获取多次导致内存无法正常回收时，就会导致内存不够用，最终导致内存溢出。

     内存溢出 （out of memory）：:指程序申请内存时，没有足够的内存供申请者使用，导致数据无法正常存储到内存中。也就是说给你个int类型的存储数据大小的空间，
     但是却存储一个long类型的数据，这样就会导致内存溢出。


     1.关系：内存泄露最终会导致内存溢出，由于系统中的内存是有限的，如果过度占用资源而不及时释放，最后会导致内存不足，从而无法给所需要存储的数据提供足够的内存，从而导致内存溢出。
     导致内存溢出也可能是由于在给数据分配大小时没有根据实际要求分配，最后导致分配的内存无法满足数据的需求，从而导致内存溢出。

     2.区别：内存泄露是由于GC无法及时或者无法识别可以回收的数据进行及时的回收，导致内存的浪费；内存溢出是由于数据所需要的内存无法得到满足，导致数据无法正常存储到内存中。内存泄露的多次表现就是会导致内存溢出

     21.常见设计模式

     22.项目中用到的开源框架的介绍

     webview的生命周期

     webview如何判断加载完成

     contentprovider 的了解，使用

     29和31关于存储的区别，如何获取

     */
}
